/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.core.windows; import java.awt.*; import java.awt.Dimension; import java.awt.event.WindowAdapter; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.WindowEvent; import java.text.MessageFormat; import java.util.*; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectOutput; import java.io.ObjectInput; import java.io.ObjectInputValidation; import java.io.IOException; import java.io.ObjectStreamException; import java.io.Serializable; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.Arrays; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.SwingUtilities; import org.openide.TopManager; import org.openide.windows.*; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; import org.openide.util.Mutex; import org.openide.util.io.NbMarshalledObject; import org.openide.NotifyDescriptor; import org.netbeans.core.MainWindow; import org.netbeans.core.windows.WeakHash.Value; import org.netbeans.core.windows.util.*; /** Implementation of manager of windows in the IDE. * Handles work with workspaces, serialization of all window system, * allows to listen to workspace events. * This class is final only for performance reasons. Can be freely * unfinaled if desired. * * @author Jaroslav Tulach, Dafe Simonek */ public final class WindowManagerImpl extends WindowManager { /** The Corona IDE's main window */ static MainWindow mainWindow; /** The only instance of the window manager implementation * in the system */ static WindowManagerImpl defaultInstance; /** State machine support */ static StateManager stateManager; /** Support for deferred opening of top components */ static DeferredPerformer deferredPerformer; /** array of workspaces */ Workspace[] workspaces; /** Current active workspace */ Workspace current; /** properties support */ transient PropertyChangeSupport changeSupport; /** the set of listeners which listen to the changes of * top component set in system * @associates TopComponentListener*/ transient HashSet tcListeners; /** The history of activated components mapped to their classes * (mapping class - top component) */ private static Hashtable lastActivatedComponents; /** initialized already? */ transient private boolean isCreated; /** map of workspace::Value (activated nodes) */ transient private WeakHash workspace2Nodes; /** helper flag */ transient private boolean serializationInProgress = false; /** true if main window was already positioned * during deserialization */ transient private boolean mainPositioned = false; /** Helper temporary variable, holds TC manager currently * being validated, used in createTopComponentManager() method */ transient private TopComponentManager validatedManager; /** Standard creator for proper initialixation of the window system */ private static DefaultCreator dc; static final long serialVersionUID =680725949680433701L; /** default base name for noname modes */ private static final String DEFAULT_NAME = "untitled_mode"; // NOI18 /** Default constructor. Don't use directly, use getDefault() * instead. */ private WindowManagerImpl () { initialize(); } /** Needed initialization, called from constrcutor and * during deserialization */ private void initialize () { changeSupport = new PropertyChangeSupport(this); workspace2Nodes = new WeakHash(); } public synchronized static WindowManagerImpl getDefault() { if (defaultInstance == null) { defaultInstance = new WindowManagerImpl(); // initialize window manager with default settings // we are not doing this in constructor to prevent from cycling if (!"full".equals (System.getProperty ("netbeans.full.hack"))) { dc = new DefaultCreator(defaultInstance); dc.start(); } } return defaultInstance; } /** @return The only instance of window manager's state support * in the system */ public static StateManager stateManager () { if (stateManager == null) { stateManager = new StateManager(); } return stateManager; } /** @return The only instance of support for deferred opening. */ public static DeferredPerformer deferredPerformer () { if (deferredPerformer == null) { deferredPerformer = new DeferredPerformer(); } return deferredPerformer; } /** Helper method - create workspaces from scratch by * adding standard workspaces and setting initial positions */ public static void createFromScratch () { if (!"full".equals (System.getProperty ("netbeans.full.hack"))) { // ensure that initialization is done getDefault(); } } /** Provides access to the MainWindow of the IDE. * This should ONLY be used for: * <UL> * <LI>Using the MainWindow as the parent for dialogs</LI> * <LI>Using the MainWindow's positions for positioning of windows * that need to be prepositioned </LI> * </UL> * @return the MainWindow of the IDE. */ public java.awt.Frame getMainWindow () { return mainWindow (); } /** Called after a current LookAndFeel change to update the IDE's UI * Should call updateUI on all opened windows */ public void updateUI () { // update main window first SwingUtilities.updateComponentTreeUI(mainWindow); mainWindow.pack(); // update all other opened windows on workspaces Workspace[] wArray = getWorkspaces(); for (int i = 0; i < wArray.length; i++) { for (Iterator iter = wArray[i].getModes().iterator(); iter.hasNext(); ) { ((ModeImpl)iter.next()).updateUI(); } } } /** Returns newly created and properly * initialized top component registry. * * @return the registry */ protected TopComponent.Registry componentRegistry () { RegistryImpl result = new RegistryImpl(); // force registry to listen to top components' events addTopComponentListener(result); return result; } /** Creates new workspace with given name. * @param name the name of the workspace * @return new workspace */ public Workspace createWorkspace (String name, String displayName) { return new WorkspaceImpl(name, displayName); } /** Finds workspace given its name. * @param name the name of workspace to find * @return workspace or null if not found */ public Workspace findWorkspace (String name) { if (workspaces == null) return null; for (int i = 0; i < workspaces.length; i++) { if (name.equals(workspaces[i].getName())) return workspaces[i]; } return null; } /** List of all currenty available workspaces. */ public Workspace[] getWorkspaces () { return workspaces; } /** Sets new workspaces. * @param workspaces array of new workspaces */ public void setWorkspaces (Workspace[] workspaces) { if (Arrays.equals(this.workspaces, workspaces)) return; Workspace[] old = this.workspaces; this.workspaces = workspaces; changeSupport.firePropertyChange( PROP_WORKSPACES, old, this.workspaces ); } /** @return Current workspace. * Can be changed by calling Workspace.activate () */ public Workspace getCurrentWorkspace () { return current; } /** Sets current workspace. * @return true if succeded, false otherwise (when workspace is not * known to this window manager...) */ public boolean setCurrentWorkspace (Workspace workspace) { if ((current != null) && (current.equals(workspace))) { return true; } // check if present boolean found = false; for (int i = 0; i < workspaces.length; i++) { if (workspaces[i].equals(workspace)) { found = true; break; } } if (!found) return false; // perform the change StateManager stateMan = stateManager(); if ((stateMan.getState() & StateManager.READY) != 0) { stateMan.setMainState(StateManager.SWITCHING); } // close all menus before workspace switch // (opened popup menus caused some serious problems) javax.swing.MenuSelectionManager.defaultManager().clearSelectedPath(); Workspace old = current; current = workspace; if (old != null) { workspace2Nodes.put(old, getSelectedNodes()); ((WorkspaceImpl)old).setVisible(false); } ((WorkspaceImpl)current).setVisible(true); // notify others changeSupport.firePropertyChange( PROP_CURRENT_WORKSPACE, old, current ); setSelectedNodes(workspace2Nodes.get(current)); if ((stateMan.getState() & StateManager.SWITCHING) != 0) { stateMan.setMainState(StateManager.READY); } return true; } /** switches to next workspace as current */ public synchronized void nextWorkspace() { Workspace current = getCurrentWorkspace(); int len = workspaces.length - 1; for (int i = len; i >= 0; i--) { if (workspaces[i] == current) { if (i == len) i = 0; // cycle it else ++i; // i will be current current = (Workspace) workspaces[i]; setCurrentWorkspace(current); return; } } } /** switche to previous workspace */ public synchronized void previousWorkspace() { Workspace current = getCurrentWorkspace(); int len = workspaces.length - 1; for (int i = len; i >= 0; i--) { if (workspaces[i] == current) { if (i == 0) i = len; // cycle it else --i; // i will be current current = (Workspace) workspaces[i]; setCurrentWorkspace(current); return; } } } /** @return selected nodes at 0 and activated at 1 */ static Value getSelectedNodes() { Node[][] ns = new Node[2][]; ns[0] = TopComponent.getRegistry().getCurrentNodes(); ns[1] = TopComponent.getRegistry().getActivatedNodes(); Value ret = new Value(); ret.activatedNodes = ns; ret.activatedTC = TopComponent.getRegistry().getActivated(); return ret; } void setSelectedNodes(Value active) { Node[][] nodes = (active == null ? null : active.activatedNodes); if (nodes == null) { nodes = new Node[2][]; nodes[0] = nodes[1] = new Node[] {}; } RegistryImpl rimpl = (RegistryImpl) TopComponent.getRegistry(); SelectedNodesChangedEvent ev = new SelectedNodesChangedEvent(nodes, null, nodes[1]); rimpl.selectedNodesChanged(ev); ev = new SelectedNodesChangedEvent(nodes, null, nodes[0]); rimpl.selectedNodesChanged(ev); if (active != null) { // activateComponent(active.activatedTC); /* TopComponentChangedEvent tcev = new TopComponentChangedEvent(nodes, active.activatedTC, null, 1 ); rimpl.topComponentActivated(tcev); */ } } // // You can add implementation to this class (+firePropertyChange), or implement it in subclass // Do as you want. // /** Attaches listener for changes in workspaces */ public void addPropertyChangeListener (PropertyChangeListener l) { changeSupport.addPropertyChangeListener(l); } /** Removes listener. */ public void removePropertyChangeListener (PropertyChangeListener l) { changeSupport.removePropertyChangeListener(l); } /** Adds top component listener for listening to the changes of * the set of top components in the system */ public synchronized void addTopComponentListener (TopComponentListener tcl) { if (tcListeners == null) tcListeners = new HashSet(5); tcListeners.add(tcl); } /** Removes top component listener */ public synchronized void removeTopComponentListener (TopComponentListener tcl) { if (tcListeners == null) return; tcListeners.remove(tcl); } /** @return True if workspace pool was created from scratch or * deserialized already, false if not initialized yet. */ public boolean isCreated () { return isCreated; } /** Sets created flag. Accessible only for class in this * package */ void setCreated (boolean isCreated) { this.isCreated = isCreated; } /** @return true if main window was already positioned */ public boolean isMainPositioned () { return mainPositioned; } /** Helper method. * @return set of listeners, which is prepared for firing. * Can return null if no listeners are attached */ Set getTcListenersForFiring () { if (tcListeners == null) return null; Set cloned = null; synchronized (this) { cloned = (Set)tcListeners.clone(); } return cloned; } /** Utility method, reactivates last activated top component * of specified class. * @param componentClass the class of the top component which should * be reactivated * @return true if some component was reactivated, false if not * (no component of specified class was activated before) */ public static boolean reactivateComponent (Class componentClass) { TopComponent last = lastActivated(componentClass); if (last != null) { last.open(); last.requestFocus(); } return last != null; } /** Returns the top component of specified class which was activated * in the past and no other top component of this class was * activated later. * @param componentClass the class of the top component * @return requested top component or null if no such top component * can be found. */ public static TopComponent lastActivated (Class componentClass) { if (lastActivatedComponents == null) return null; return (TopComponent)lastActivatedComponents.get(componentClass); } /** Utility method, finds unused name of the mode on given workspace * based on given string. * @param base Base name of the mode. Can be null - in this cas * some default string constant will be used * @return string representing mode name which is not used yet * on current workspace */ public static String findUnusedModeName (String base, Workspace workspace) { // be prepared when base is null if (base == null) { base = DEFAULT_NAME; } if (workspace.findMode(base) == null) return base; // add numbers to the name String result = null; int modeNumber = 1; while (workspace.findMode(result = base + " " + modeNumber) != null) { // NOI18N modeNumber++; } return result; } /** Enable classes from this package to call this method * and registers component into history of activated top components. */ protected void activateComponent (TopComponent tc) { /*System.out.println("Activating: " + ((tc == null) ? "NONE" : tc.getName()));*/ // NOI18N if (tc != null) { // add to activated history if (lastActivatedComponents == null) lastActivatedComponents = new Hashtable(); //System.out.println("Registering: " + tc.getClass().getName()); // NOI18N registerComponent(tc.getClass(), tc); } // fire info that activated component changed Set listeners = getTcListenersForFiring(); if (listeners != null) { for (Iterator iter = listeners.iterator(); iter.hasNext(); ) { ((TopComponentListener)iter.next()).topComponentActivated( new TopComponentChangedEvent(this, tc, getCurrentWorkspace(), TopComponentChangedEvent.ACTIVATED)); } } super.activateComponent(tc); } /** Adds given pair class - top component to the activated history */ static void registerComponent (Class c, TopComponent comp) { if (c == null) return; Object orig = lastActivatedComponents.put (c, comp); // recurse for super class and super interfaces registerComponent(c.getSuperclass (), comp); Class[] inter = c.getInterfaces (); for (int i = 0; i < inter.length; i++) { registerComponent(inter[i], comp); } } /** Removes given pair class - top component from activated history */ static void unregisterComponent (Class c, TopComponent comp) { if (c == null) return; // if different comp is attached to class c stop removing if (comp != lastActivatedComponents.get(c)) return; lastActivatedComponents.remove (c); // recurse for super class and super interfaces unregisterComponent(c.getSuperclass (), comp); Class[] inter = c.getInterfaces (); for (int i = 0; i < inter.length; i++) { unregisterComponent(inter[i], comp); } } /** Creates a component manager for given top component. * @param c the component * @return the manager that handles opening, closing and * selecting a component */ protected synchronized org.openide.windows.WindowManager.Component createTopComponentManager (TopComponent c) { /*if (validatedManager != null) { System.out.println("Validating for " + validatedManager.componentName); System.out.println("TC class: " + c.getClass().getName()); }*/ // create new manager or returng manager being validated org.openide.windows.WindowManager.Component result = (validatedManager == null) ? new TopComponentManager(c) : validatedManager; // clear after each usage validatedManager = null; return result; } /** Helper; used from TopComponentManager to identify itself * during deserialization to achieve asociation with its top component */ private void setValidatedManager (TopComponentManager tcm) { validatedManager = tcm; } private TopComponentManager getValidatedManager () { return validatedManager; } /** Finds top component manager for given top component. * It's here just to rovide access for classes in this package. */ public static TopComponentManager findManager (TopComponent tc) { return (TopComponentManager) /*WindowManager. not compilable by JIKES */findComponentManager(tc); } /** Convenience static method for simpler obtaining mainWindow * reference */ public static final MainWindow mainWindow () { if (mainWindow == null) { synchronized (WindowManagerImpl.class) { if (mainWindow == null) { mainWindow = new MainWindow (); mainWindow.addWindowListener(new IconifyManager()); } } } return mainWindow; } /** Delegates serialization manager instance to be serialized * instead of window manager impl */ private Object writeReplace () throws ObjectStreamException { return new SerializationReplacer(); } /** Instance of this class is serialized instead of WindowManagerImpl. * It saves all needed information and deserializesback to the signleton * instance of WindowManagerImpl */ private static final class SerializationReplacer implements Serializable { static final long serialVersionUID =-8212722893309295268L; // deserialized workspaces transient Workspace[] workspaces; // deserialized current workspaces transient Workspace current; // flag for recognizing first startup transient boolean isStartup = true; /** Deserialization of the workspace */ private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException { // obtain WindowManagerImpl whose serialization we manage WindowManagerImpl wm = WindowManagerImpl.getDefault(); StateManager stateMan = wm.stateManager(); stateMan.setMainState(StateManager.DESERIALIZING); try { // remove old workspaces, (but don't do this on the // first startup, as modules can have their own // workspaces already installed) if (!isStartup) { wm.setWorkspaces(new Workspace[0]); } // read workspaces - first phase //System.out.println("First phase - reading..."); // NOI18N int count = ois.readInt(); workspaces = new Workspace[count]; for (int i = 0; i < count; i++) { workspaces[i] = (Workspace)ois.readObject(); } // read current workspace current = (Workspace)ois.readObject(); // read bounds of main window wm.mainWindow().setBounds((Rectangle)ois.readObject()); //System.out.println("Workspaces read suceesfully!"); // NOI18N // testing //throw new IOException(); } finally { isStartup = false; stateMan.setMainState(StateManager.READY); //System.out.println("Workspace reading finished."); // NOI18N } } /** Resolves deserialized SerializationReplacer to the singleton * instance of WindowManagerImpl */ private synchronized Object readResolve () throws ObjectStreamException { // obtain WindowManagerImpl whose serialization we manage WindowManagerImpl wm = WindowManagerImpl.getDefault(); StateManager stateMan = wm.stateManager(); stateMan.setMainState(StateManager.DESERIALIZING); try { wm.mainPositioned = true; // validating workspaces and modes //System.out.println("Second phase - validate workspaces and modes..."); // NOI18N for (int i = 0; i < workspaces.length; i++) { ((WorkspaceImpl)workspaces[i]).validateSelf(); } // set new workspaces wm.setWorkspaces(workspaces); // validate top components //System.out.println("Third phase - validate top components..."); // NOI18N for (int i = 0; i < workspaces.length; i++) { ((WorkspaceImpl)workspaces[i]).validateData(); } wm.setCurrentWorkspace(current); //System.out.println("WS validated succesfully."); // NOI18N } finally { stateMan.setMainState(StateManager.READY); } // reactivate return wm; } /** Serialization of all workspaces */ private void writeObject (ObjectOutputStream oos) throws IOException { //System.out.println("Writing workapaces..."); // NOI18N // obtain WindowManagerImpl whose serialization we manage WindowManagerImpl wm = WindowManagerImpl.getDefault(); StateManager stateMan = wm.stateManager(); stateMan.setMainState(StateManager.SERIALIZING); try { // write workspaces Workspace[] workspaces = wm.workspaces; if (workspaces == null) { oos.writeInt(0); } else { oos.writeInt(workspaces.length); for (int i = 0; i < workspaces.length; i++) { oos.writeObject(workspaces[i]); } } // write current workspace oos.writeObject(wm.current); // write bounds of main window oos.writeObject(wm.mainWindow().getBounds()); } finally { stateMan.setMainState(StateManager.READY); } //System.out.println("Workspaces written."); // NOI18N } } // end of inner class SerializationReplacer /** Manager for iconifying/deiconifying main window */ static final class IconifyManager extends WindowAdapter { /** The workspace to be shown on deiconification */ private WorkspaceImpl workspace; public void windowIconified (WindowEvent evt) { RequestProcessor.postRequest (new Runnable () { public void run () { iconify (); } }, 200); } public void windowDeiconified (WindowEvent evt) { if (workspace != null) { workspace.setVisible(true); } } /** Iconify all modes on current workspace */ private void iconify () { workspace = (WorkspaceImpl)TopManager.getDefault(). getWindowManager().getCurrentWorkspace(); workspace.setVisible(false); } } // end of IconifyManager /** The manager that handles operations on a top component. * It is always attached to a TopComponent via one-to-one * relationship. * * @author Dafe Simonek */ static final class TopComponentManager extends ComponentAdapter implements WindowManager.Component, DeferredPerformer.DeferredCommand { /** The constants for properties of managed top component */ public static final String PROP_ACTIVATED_NODES = "activatedNodes"; // NOI18N public static final String PROP_NAME = "name"; // NOI18N public static final String PROP_ICON = "icon"; // NOI18N /** Set of workspaces where top component is opened. */ transient HashSet whereOpened; /** Agregation of the top component which we're trying to manage */ TopComponent component; /** top component we manage in hlaf-way deserialized form, * used only during deserialization */ private NbMarshalledObject marshalledComponent; /** helper variable, holds top component's name, used when * reporting failure of deserialization of the top copmponent */ String componentName; /** Icon of the component we manage */ transient Image icon; /** Activated nodes of the component we manage */ transient Node[] nodes; /** Nodes which will be set as activated when the component becomes non-null */ transient Node[] tempNodes; /** asociation with the window manager */ transient WindowManagerImpl wm; /** Support for property changes */ transient PropertyChangeSupport changeSupport; /** if true, the body of open method is performed even if managed * top component is already opened */ transient boolean forceOpen = false; /** asociation with support for deferred opening */ transient DeferredPerformer deferredPerformer; /** helper flag, holds current state of validation during * deserialization */ private transient int innerState = READY; /** constant for all-right state */ private static final int READY = 1; /** constant for state when validation was not performed yet */ private static final int INVALID = 2; /** constant for state when deserialization of tc completely failed */ private static final int FAILED = 4; /** manager of versioned serialization */ private static VersionSerializator serializationManager; static final long serialVersionUID =5669852754182098300L; /** Constructs new top component manager. Allow only classes in package * to construct us * @param component Managed top component. */ TopComponentManager (TopComponent component) { this.component = component; whereOpened = new HashSet(5); initialize(); } /** Initialization of this manager, called also when deserializaing */ private void initialize () { this.wm = (WindowManagerImpl)TopManager.getDefault().getWindowManager(); changeSupport = new PropertyChangeSupport(this); deferredPerformer = deferredPerformer(); } /** Opens a component on current workspace. If main window is * not visible, open action is delayed until it's open. */ public void open () { open(null); } /** Opens a component on given workspace. If window system is * in inconsistent state (main window is not visible, serializing etc..) 8 open action is delayed. * @workspace the workspace where to open managed top component */ public void open (Workspace workspace) { if (deferredPerformer.canImmediatelly()) { // immediate open doOpen((workspace == null) ? wm.getCurrentWorkspace() : workspace); } else { // deferred open deferredPerformer.putRequest(this, workspace); } } /** Implementation of DeferredPerformer.DeferredCommand interface. * Actually opens managed top component. */ public void performCommand (Object context) { /*if (component == null) { System.out.println("ASOCIATED COMPONENT IS NULL!!!!!"); Thread.dumpStack(); }*/ component.open((Workspace)context); } /** Opens a component on given workspace. * If given workspace differs from current, component will * be visible only after switching to given workspace. * @workspace the workspace where to open managed top component */ private void doOpen (Workspace workspace) { /*System.out.println("Opening " + component.getName() + " on " + workspace.getName());*/ // PENDING -> editor TC open on all workspaces at once if ((!whereOpened.add(workspace)) && (!forceOpen)) { return; }; Mode mode = workspace.findMode(component); if (mode == null) { // create new mode for given tc // important bugfix - create properly named mode even // for top components with null name String modeName = wm.findUnusedModeName(component.getName(), workspace); mode = ((WorkspaceImpl)workspace).createMode( modeName, modeName, null, ModeImpl.MULTI_TAB, true ); } mode.dockInto(component); // let others know that top component was opened... Set listeners = wm.getTcListenersForFiring(); if (listeners != null) { for (Iterator iter = listeners.iterator(); iter.hasNext(); ) { ((TopComponentListener)iter.next()).topComponentOpened( new TopComponentChangedEvent(this, component, workspace, TopComponentChangedEvent.OPENED)); } } } /** @return true if managed top component is currently opened * on some workspace, false otherwise */ public boolean isOpened () { return whereOpened.size() > 0; } /** @return true if managed top component is currently opened * on given workspace, false otherwise */ public boolean isOpened (Workspace workspace) { return whereOpened.contains(workspace); } /** Closes the component on given workspace. * @param workspace the workspace where managed top component * should be closed. */ public void close (Workspace workspace) { switch (component.getCloseOperation()) { case TopComponent.CLOSE_LAST: if (isOpened(workspace)) doClose(workspace); break; case TopComponent.CLOSE_EACH: // special mode for editor etc... // close on all workspaces Workspace[] workspaces = wm.getWorkspaces(); for (int i = 0; i < workspaces.length; i++) { if (isOpened(workspaces[i])) doClose(workspaces[i]); } break; } } /** The component requests focus. Works only on opened component. * When the request comes too early, implemetation waits * till component is shown. */ public void requestFocus () { if (!isOpened()) return; if (component.isDisplayable()) Mutex.EVENT.readAccess(new Runnable() { public void run () { ((ModeImpl)getMode()).requestFocus(component); } }); else { // component not yet shown, we must wait // until the component is shown component.addComponentListener(this); } } /** @return the mode which belongs to managed top component on * CURRENT workspace. */ Mode getMode () { return wm.getCurrentWorkspace().findMode(component); } /** Actually perform the work of closing ther managed component on * given workspace, without checking. */ void doClose (Workspace workspace) { ModeImpl mode = (ModeImpl)workspace.findMode(component); whereOpened.remove(workspace); if (mode != null) { mode.close(component); } // remove from activated history if conditions satisfied if (WindowManagerImpl.lastActivatedComponents != null) { WindowManagerImpl.unregisterComponent(component.getClass(), component); /*System.out.println ("Removed from act history... " + component.getClass());*/ } // let others know that top component was closed... Set listeners = wm.getTcListenersForFiring(); if (listeners != null) { for (Iterator iter = listeners.iterator(); iter.hasNext(); ) { ((TopComponentListener)iter.next()).topComponentClosed( new TopComponentChangedEvent(this, component, workspace, TopComponentChangedEvent.CLOSED)); } } } /** Getter for set of activated nodes * @return activated nodes for the component */ public Node[] getActivatedNodes () { //System.out.println ("Getting nodes, size: " + result.length); // NOI18N return nodes; } /** Setter for set of activated nodes for the component * @param nodes activated nodes for this component */ public void setActivatedNodes (Node[] nodes) { if (component == null) { // store the nodes to a temporary variable and set them properly // when a non-null value of the component is set tempNodes = nodes; return; } //System.out.println ("Setting nodes, size: " + nodes.length); // NOI18N //System.out.println ("Opened?: " + opened); // NOI18N if (Arrays.equals(this.nodes, nodes)) return; Node[] old = this.nodes; this.nodes = nodes; // notify all that are interested... changeSupport.firePropertyChange(PROP_ACTIVATED_NODES, old, nodes); Set listeners = wm.getTcListenersForFiring(); if (listeners != null) { for (Iterator iter = listeners.iterator(); iter.hasNext(); ) { ((TopComponentListener)iter.next()).selectedNodesChanged( new SelectedNodesChangedEvent(this, component, nodes)); } } } /** Notify about name change. */ public void nameChanged () { // component can be null for a while during deserialization if (component != null) { changeSupport.firePropertyChange(PROP_NAME, null, component.getName()); } } /** Sets the icon of the top component which will be used for * component representaion on the screen. * @param icon New components' icon. */ public void setIcon (final Image icon) { if (((this.icon != null) && this.icon.equals(icon)) || ((this.icon == null) && (icon == null))) return; Image old = this.icon; this.icon = icon; changeSupport.firePropertyChange(PROP_ICON, old, this.icon); } public Image getIcon () { return icon; } /** Getter for managed component * @return managed component */ public TopComponent getComponent () { return component; } /** @return the set of workspaces where managed component is open */ public Set whereOpened () { return whereOpened; } /** Adds listener for listening to top component property changes. */ public void addPropertyChangeListener (PropertyChangeListener pchl) { changeSupport.addPropertyChangeListener(pchl); } /** Removes property change listener. */ public void removePropertyChangeListener (PropertyChangeListener pchl) { changeSupport.removePropertyChangeListener(pchl); } /** Called when managed top component becomes * visible - just for the requestFocus, when * it comes too early. */ public void componentShown (ComponentEvent ev) { // notify me no more component.removeComponentListener(this); // now request a focus SwingUtilities.invokeLater(new Runnable() { public void run () { component.requestFocus(); } }); } /** Accessor to the versioned serialization manager */ private VersionSerializator serializationManager () { if (serializationManager == null) { serializationManager = createSerializationManager(); } return serializationManager; } /** Creates new serialization manager filled with our versions */ private static VersionSerializator createSerializationManager () { VersionSerializator result = new VersionSerializator(); result.putVersion(new Version1()); return result; } /** Serialization */ private Object writeReplace () throws ObjectStreamException { // provide version with data Version1 version = (Version1)serializationManager().getVersion(Version1.NAME); try { version.assignData(this, new NbMarshalledObject(component)); } catch (Exception exc) { notifyPersistenceError(exc, component.getName(), false); // write null as a marker that there was serialization problem return null; } // use replacer return new DefaultReplacer(new VSAccess(serializationManager())); } /** Called when first phase of WS deserialization is done. * Deserialization of managed TC is finished here. */ public boolean validateData () { // deserialize only once, then only return succes or failure // status if (innerState != INVALID) { return innerState == READY; } // component written badly, consider it a failure if (marshalledComponent == null) { innerState = FAILED; return false; } // Actually deserializes top component. // Uses ugly hack - redundant TopComponent<init>.getManager() call // to enforce wm.createTopComponentManager() to be called, // in which we can re-asociate deserialized top component // with this manager. // This is UGLY implementation, based on the fact that there's // no way to set new manager for top component and we want to // keep the Open API unchanged if possible try { wm.setValidatedManager(this); component = (TopComponent)marshalledComponent.get(); // component can resolve itself to null, // be prepared to such situation /*if (component != null) { component.getActivatedNodes(); }*/ innerState = (component == null) ? FAILED : READY; if ((component != null) && (tempNodes != null)) { setActivatedNodes(tempNodes); tempNodes = null; } } catch (Exception exc) { // do catch all exceptions, because exceptions // during deserialization of one top component // shoudn't break whole window system innerState = FAILED; notifyPersistenceError(exc, componentName, true); return false; } finally { // ensure that manager is not set anymore wm.setValidatedManager(null); } return innerState == READY; } /** Notify user about exception during top component * serialization or deserialization */ private void notifyPersistenceError (final Exception exc, final String tcName, final boolean reading) { Runnable performer = new Runnable () { public void run () { if (System.getProperty("netbeans.debug.exceptions") != null) { exc.printStackTrace(); } String message = null; if (reading) { message = MessageFormat.format( NbBundle.getBundle(WindowManagerImpl.class).getString("FMT_TCReadError"), new Object[] { tcName } ); } else { message = MessageFormat.format( NbBundle.getBundle(WindowManagerImpl.class).getString("FMT_TCWriteError"), new Object[] { tcName } ); } TopManager.getDefault().notify( new NotifyDescriptor.Exception(exc, message) ); } }; if (reading) { SwingUtilities.invokeLater(performer); } else { performer.run(); } } /** Basic version of persistence for mode implementation. * Method assignData(modeImpl) must be called prior to serialization */ private static final class Version1 implements DefaultReplacer.ResVersionable { /* identification string */ public static final String NAME = "Version_1.0"; // NOI18N /** variables of persistent state of the tc manager */ String componentName; NbMarshalledObject marshalledComponent; /** asociation with outerclass, used when writing */ TopComponentManager tcm; /** set of workspaces where managed tc is opened */ transient HashSet whereOpened; /** Identification of the version */ public String getName () { return "Version_1.0"; // NOI18N } /** Assigns data to be written. Must be called before writing */ public void assignData (TopComponentManager tcm, NbMarshalledObject marshalledComponent) { this.tcm = tcm; this.marshalledComponent = marshalledComponent; } /** read the data of the version from given input */ public void readData (ObjectInput in) throws IOException, ClassNotFoundException { // read the fields componentName = (String)in.readObject(); marshalledComponent = (NbMarshalledObject)in.readObject(); } /** write the data of the version to given output */ public void writeData (ObjectOutput out) throws IOException { out.writeObject(tcm.getComponent().getName()); // write top component itself using marshalled object out.writeObject(marshalledComponent); } /** Resolves this object to top component manager instance again */ public Object resolveData () throws ObjectStreamException { TopComponentManager result = new TopComponentManager(null); result.componentName = componentName; result.marshalledComponent = marshalledComponent; result.innerState = INVALID; return result; } } // end of Version1 inner class /** Implementation of persistent access to our version serializator */ private static final class VSAccess implements DefaultReplacer.Access { /** serialVersionUID */ private static final long serialVersionUID = -6484558550904999459L; /** version serializator, used only during writing */ transient VersionSerializator vs; public VSAccess (VersionSerializator vs) { this.vs = vs; } public VersionSerializator getVersionSerializator () { return (vs == null) ? createSerializationManager() : vs; } } // end of VSAccess inner class } // end of TopComponentManager inner class } /* * Log * 47 Gandalf 1.46 3/8/00 David Simonek bugfix - exception in * explore from here operation * 46 Gandalf 1.45 2/25/00 David Simonek #5859 bugfix * 45 Gandalf 1.44 2/25/00 Petr Jiricka Bugfix 5603, see this for * evaluation and description of fix. * 44 Gandalf 1.43 2/18/00 David Simonek #5708 bugfix * 43 Gandalf 1.42 2/15/00 David Simonek bug after unmount of * opened editor files fixed (hopefully..:-) * 42 Gandalf 1.41 1/17/00 David Simonek SerializationReplacer * serialization UID added * 41 Gandalf 1.40 1/17/00 Jesse Glick No more * TemplatesExplorer. * 40 Gandalf 1.39 1/15/00 David Simonek popup menu *stuck* bug * fixed, mutliwindow title bug fixed * 39 Gandalf 1.38 1/13/00 David Simonek i18n * 38 Gandalf 1.37 1/12/00 Ian Formanek NOI18N * 37 Gandalf 1.36 1/9/00 David Simonek modified initialization * of the WindowManagerImpl * 36 Gandalf 1.35 12/23/99 David Simonek last activated * registratiron modified * 35 Gandalf 1.34 12/17/99 David Simonek #1913, #2970 * 34 Gandalf 1.33 12/6/99 David Simonek property sheet now opens * automatically on editing workspace, other positioning updated * 33 Gandalf 1.32 11/10/99 David Simonek debug comments removed * 32 Gandalf 1.31 11/6/99 David Simonek serialization bug fixing * 31 Gandalf 1.30 11/4/99 David Simonek ws serialization bugfixes * 30 Gandalf 1.29 11/3/99 David Simonek ws now respects resolving * of tc to null again * 29 Gandalf 1.28 11/3/99 David Simonek completely rewritten * serialization of windowing system... * 28 Gandalf 1.27 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 27 Gandalf 1.26 10/8/99 David Simonek serialization of window * manager impl is now done in SerializationReplacer (solves problems in * projects module) * 26 Gandalf 1.25 10/7/99 David Simonek debug prints removed... * 25 Gandalf 1.24 10/6/99 David Simonek more robust serialization * of window system (especially editor TCs) * 24 Gandalf 1.23 9/8/99 David Simonek deferred opening and * firing of selected nodes, state management * 23 Gandalf 1.22 8/19/99 David Simonek unfinaled parameters * 22 Gandalf 1.21 8/17/99 David Simonek persistent main window * positioning issues * 21 Gandalf 1.20 8/14/99 David Simonek bugfixes, #3347, #3274 * etc. * 20 Gandalf 1.19 8/9/99 David Simonek * 19 Gandalf 1.18 8/9/99 Ian Formanek Generated Serial Version * UID * 18 Gandalf 1.17 8/9/99 Miloslav Metelka Paste action enabling in * editor * 17 Gandalf 1.16 8/1/99 David Simonek debug prints commented * 16 Gandalf 1.15 8/1/99 David Simonek * 15 Gandalf 1.14 7/31/99 David Simonek small additions * 14 Gandalf 1.13 7/30/99 David Simonek serialization fixes * 13 Gandalf 1.12 7/30/99 David Simonek iconification bugfixes, * focus bugfixes * 12 Gandalf 1.11 7/29/99 David Simonek further ws serialization * changes * 11 Gandalf 1.10 7/28/99 David Simonek workspace serialization * bugfixes * 10 Gandalf 1.9 7/28/99 David Simonek serialization of window * system...first draft :-) * 9 Gandalf 1.8 7/23/99 David Simonek another fixes (closing a * component) * 8 Gandalf 1.7 7/22/99 Libor Kramolis * 7 Gandalf 1.6 7/21/99 David Simonek window system updates... * 6 Gandalf 1.5 7/20/99 David Simonek various window system * updates * 5 Gandalf 1.4 7/16/99 Ales Novak bugfix * 4 Gandalf 1.3 7/16/99 Ales Novak windows placing * 3 Gandalf 1.2 7/15/99 Ales Novak nodes actions * enable/disable * 2 Gandalf 1.1 7/13/99 Ales Novak optimized * 1 Gandalf 1.0 7/11/99 David Simonek * $ */